﻿using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Shell.Common;

namespace Shell.KnowledgeBase
{
    public class Base
    {
        readonly List<Implication> _implications = new List<Implication>();
        readonly List<Statement> _statements = new List<Statement>();
        readonly List<SyntaxRule> _syntaxRules = new List<SyntaxRule>();
        readonly List<Transaction> _transactions = new List<Transaction>();

        private const string WordElement = "word";

        private const string TransactionElement = "transaction";
        private const string TransactionContextStatementElement = "given";
        private const string TransactionMessageStatementElement = "message";

        private const string OnthologyStatementElement = "statement";

        private const string ImplicationRuleElement = "implication";
        private const string ImplicationRuleAntecedentElement = "antecedent";
        private const string ImplicationRuleConsequentElement = "consequent";

        private const string SyntaxElement = "syntax";
        private const string SyntaxSymbolAttribute = "symbol";
        private const string SyntaxTextElement = "text";
        
        public IEnumerable<Statement> Statements
        {
            get { return _statements; }
        }

        public IEnumerable<Implication> Implications
        {
            get { return _implications; }
        }

        public IEnumerable<SyntaxRule> SyntaxRules
        {
            get { return _syntaxRules; }
        }

        public IEnumerable<Transaction> Transactions
        {
            get { return _transactions; }
        }

        public void LoadFromXml(string fileName)
        {
            var document = XDocument.Load(fileName);

            foreach (var element in document.Root.Elements())
            {
                if (element.Name == ImplicationRuleElement)
                {
                    var variableMap = new Dictionary<string, Variable>();
                    _implications.Add(
                        new Implication(
                            ReadStatements(element,ImplicationRuleAntecedentElement, variableMap),
                            ReadStatement(element.Element(ImplicationRuleConsequentElement), variableMap)));
                }
                else if (element.Name == OnthologyStatementElement)
                {
                    _statements.Add(ReadStatement(element, new Dictionary<string, Variable>()));
                }
                else if (element.Name ==  SyntaxElement)
                {
                    var variableMap = new Dictionary<string, Variable>();
                    var synonyms = ReadStatements(element, SyntaxTextElement, variableMap);

                    ProcessParaphrase(element.Attribute(SyntaxSymbolAttribute).Value, synonyms);
                }
                else if (element.Name == TransactionElement)
                {
                    var variableMap = new Dictionary<string, Variable>();

                    _transactions.Add(
                        new Transaction
                                       {
                                           Statements = ReadStatements(element, TransactionContextStatementElement, variableMap),
                                           Messages = ReadStatements(element, TransactionMessageStatementElement, variableMap)
                                       }
                        );
                }
                else if (element.Name == WordElement)
                {
                    _syntaxRules.Add(
                        new SyntaxRule(
                            ReduceMultipleWhitespaces(element.Value)
                                .Replace(' ', '-')
                                .CreateAtomicStatement(),
                            element.Value.ToStatementLetterwise(new Dictionary<string, Variable>())));
                }
            }
        }

        private static string ReduceMultipleWhitespaces(string value)
        {
            return Regex.Replace(value, @"\value+", " ");
        }

        private static Statement ReadStatement(XElement element, IDictionary<string, Variable> variableMap)
        {
            return element.Value.ToStatementLetterwise(variableMap);
        }

        private static Statement[] ReadStatements(XElement element, string elementName,IDictionary<string, Variable> variableMap)
        {
            return element.Elements(elementName)
                          .Select(_ => _.Value)
                          .Select(_ => _.ToStatementLetterwise(variableMap))
                          .ToArray();
        }

        private void ProcessParaphrase(string hint, IEnumerable<Statement> statements)
        {
            var abstraction = new Statement(
                new Atom(hint)
                    .Yield<Term>()
                    .Concat(
                        statements
                            .SelectMany(_ => _)
                            .OfType<Variable>()
                            .Distinct()
                            .ToArray()));

            var syntaxRules = statements.Select(_ => new SyntaxRule(abstraction, _));

            _syntaxRules.AddRange(syntaxRules);
        }
    }
}